with GNAT.String_Split; use GNAT.String_Split;

--
-- separate HTTP headers from content
--

package body Headers_Parser is

   Lines : Slice_Set;

   --
   -- Retrieve Headers only
   --
   --       without HTTP content
   --

   function Parse_Headers( HTTP_Data : in HTTP_String_Sub_Type )

         return String
   is

      Headers_End : Positive := 1;

   begin

      if( Lines_Present( HTTP_Data ) < 1 ) then

         raise HTTP_Data_Empty;

      end if;

      String_Output_Type.Delete( String_Output,
            1,
            String_Output_Type.Length( String_Output ));

      --
      -- iterate through lines until find line non-empty, varying from header
      --    regular expression
      --

      for Line_Number in HTTP_Data'First .. Lines_Present( HTTP_Data ) loop

         if( not Match( Slice( Lines, Slice_Number( Line_Number )),

                        Header_RegEx ))
         then

            Headers_End := Line_Number;
            exit;

         else

            String_Output_Type.Append( String_Output,

              Slice( Lines, Slice_Number( Line_Number ))

              & Ascii.LF );

         end if;

      end loop;

      if( Headers_End = 1 ) then

         raise Headers_Not_Found;

      end if;

      return String_Output_Type.To_String( String_Output );


   end Parse_Headers;


   --
   -- Retrieve HTTP content only
   --
   --       without Headers
   --

   function Parse_Content( HTTP_Data : in HTTP_String_Sub_Type )

         return String
   is

   begin

      if( Lines_Present( HTTP_Data ) < 1 ) then

         raise HTTP_Data_Empty;

      end if;

      String_Output_Type.Delete( String_Output,
            1,
            String_Output_Type.Length( String_Output ));

      --
      -- iterate through lines until find first line not matching header
      --       regular expression
      --
      -- collect remaining lines as content
      --

      for Line_Number in HTTP_Data'First .. Lines_Present( HTTP_Data ) loop

         if( Match( Slice( Lines, Slice_Number( Line_Number )),

                    Header_RegEx ))
         then

            null;

         else

            for Content_Line_Number in Line_Number ..

                  Lines_Present( HTTP_Data )

            loop

               String_Output_Type.Append( String_Output,

                     Slice( Lines, Slice_Number( Content_Line_Number ))

                     & Ascii.LF );

            end loop;

            exit;

         end if;

      end loop;

      if( String_Output_Type.Length( String_Output ) < 1 ) then

         raise Content_Not_Found;

      end if;

      return String_Output_Type.To_String( String_Output );


   end Parse_Content;


   --
   -- divide HTTP String by linefeeds
   --

   function Lines_Present( HTTP_Data : in HTTP_String_Sub_Type )

         return Integer
   is

      Multiple_Lines_Not_Found : exception;

      LINEFEED : constant String( 1..1 ) := ( 1 => Ascii.LF );

   begin

      --
      -- cached results, return from result stored at package level
      --
      --    Slice Create is expensive for large Strings
      --

      if( Integer( Slice_Count( Lines ) ) > 1 ) then

         return Integer( Slice_Count( Lines ) );

      end if;

      Create( S          => Lines,
              From       => HTTP_Data,
              Separators => LINEFEED,
              Mode       => Multiple );

      if( Integer( Slice_Count( Lines ) ) < 2 ) then

         raise Multiple_Lines_Not_Found;

      end if;

      return Integer( Slice_Count( Lines ) );


   end Lines_Present;


   --
   -- remove cached String divided by line feeds
   --

   procedure Clear is

      Empty_Lines : Slice_Set;

   begin

      Lines := Empty_Lines;

   end Clear;


end Headers_Parser;